package com.web3.management.service;

import com.web3.management.entity.Account;
import com.web3.management.entity.TradeLog;
import com.web3.management.repository.AccountRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;

/**
 * 交易监控服务
 * 基于交易日志进行异常检测和告警
 *
 * @author Web3 Management Team
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TransactionMonitorService {

    private final SystemSettingService systemSettingService;
    private final AccountRepository accountRepository;
    private final RestTemplate restTemplate;

    /**
     * 处理交易日志监控
     *
     * @param tradeLog 交易日志
     */
    @Transactional
    public void processTransactionMonitor(TradeLog tradeLog) {
        try {
            // 计算磨损率：磨损金额 ÷ 交易总金额
            BigDecimal slippageRate = calculateSlippageRate(
                    tradeLog.getSlippage(),  // 使用磨损字段
                    tradeLog.getActualAmount()  // 使用实际交易金额作为总金额
            );

            // 更新交易日志的监控字段
            tradeLog.setSlippageRate(slippageRate);

            // 检查是否异常
            boolean isAbnormal = checkIfAbnormal(slippageRate);
            tradeLog.setIsAbnormal(isAbnormal);

            // 如果异常且未发送告警，则发送告警
            if (isAbnormal && !Boolean.TRUE.equals(tradeLog.getAlertSent())) {
                sendAbnormalAlert(tradeLog, slippageRate);
                tradeLog.setAlertSent(true);

                // 暂停账号脚本
                pauseAccountScript(tradeLog.getAccountId());
            }

        } catch (Exception e) {
            log.error("处理交易监控失败: tradeLogId={}", tradeLog.getId(), e);
        }
    }

    /**
     * 计算磨损率
     *
     * @param slippageAmount  磨损金额（来自slippage字段）
     * @param totalAmount     交易总金额（实际交易金额）
     * @return 磨损率
     */
    private BigDecimal calculateSlippageRate(BigDecimal slippageAmount, BigDecimal totalAmount) {
        // 如果交易金额为空或为0，返回0
        if (totalAmount == null || totalAmount.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }

        // 如果磨损金额为空，返回0
        if (slippageAmount == null) {
            return BigDecimal.ZERO;
        }

        // 磨损率 = |磨损金额| / 交易总金额
        BigDecimal absSlippage = slippageAmount.abs();
        return absSlippage.divide(totalAmount, 8, RoundingMode.HALF_UP);
    }

    /**
     * 检查是否为异常交易
     *
     * @param slippageRate 滑点率
     * @return 是否异常
     */
    private boolean checkIfAbnormal(BigDecimal slippageRate) {
        Map<String, Object> monitorConfig = systemSettingService.getMonitorConfig();

        Boolean enabled = (Boolean) monitorConfig.get("enabled");
        if (!Boolean.TRUE.equals(enabled)) {
            return false;
        }

        Object thresholdObj = monitorConfig.get("slippage_threshold");
        double threshold = 0.0003; // 默认万分之3

        if (thresholdObj instanceof Double) {
            threshold = (Double) thresholdObj;
        } else if (thresholdObj instanceof Integer) {
            threshold = ((Integer) thresholdObj).doubleValue();
        }

        return slippageRate.compareTo(BigDecimal.valueOf(threshold)) > 0;
    }

    /**
     * 发送异常告警
     *
     * @param tradeLog     交易日志
     * @param slippageRate 滑点率
     */
    private void sendAbnormalAlert(TradeLog tradeLog, BigDecimal slippageRate) {
        try {
            // 获取通知配置
            Map<String, Object> notificationConfig = systemSettingService.getNotificationConfig();

            Boolean enabled = (Boolean) notificationConfig.get("enabled");
            String webhookUrl = (String) notificationConfig.get("webhook_url");

            if (!Boolean.TRUE.equals(enabled) || !hasValue(webhookUrl)) {
                log.info("通知功能未启用或未配置通知地址");
                return;
            }

            // 获取账号信息
            Account account = accountRepository.findById(tradeLog.getAccountId())
                    .orElse(null);

            if (account == null) {
                // 创建默认账号对象
                account = new Account();
                account.setName("未知账号");
            }

            // 构建告警消息
            String message = formatAlertMessage(tradeLog, account, slippageRate);

            // 发送企业微信告警
            sendWeChatAlert(webhookUrl, message);

            log.info("异常交易告警发送成功: accountId={}, txHash={}",
                    tradeLog.getAccountId(), tradeLog.getTxHash());

        } catch (Exception e) {
            log.error("发送异常告警失败: tradeLogId={}", tradeLog.getId(), e);
        }
    }

    /**
     * 格式化告警消息
     */
    private String formatAlertMessage(TradeLog tradeLog, Account account, BigDecimal slippageRate) {
        return String.format(
                "🚨 交易异常告警\n\n" +
                "账号: %s\n" +
                "币种: %s\n" +
                "计划交易量: %s\n" +
                "实际交易量: %s\n" +
                "磨损量: %s\n" +
                "磨损率: %.4f%%\n" +
                "交易哈希: %s\n\n" +
                "系统已自动暂停该账号的交易脚本，请管理员及时处理。",
                account.getName(),
                getSymbolFromRemark(tradeLog.getRemark()),
                tradeLog.getPlannedAmount(),
                tradeLog.getActualAmount(),
                tradeLog.getSlippage(), // 直接使用磨损字段
                slippageRate.multiply(BigDecimal.valueOf(100)),
                tradeLog.getTxHash()
        );
    }

    /**
     * 发送企业微信告警
     */
    private void sendWeChatAlert(String webhookUrl, String message) {
        try {
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("msgtype", "text");

            Map<String, String> textContent = new HashMap<>();
            textContent.put("content", message);
            requestBody.put("text", textContent);

            restTemplate.postForObject(webhookUrl, requestBody, String.class);

        } catch (Exception e) {
            log.error("发送企业微信告警失败: webhookUrl={}", webhookUrl, e);
            throw e;
        }
    }

    /**
     * 暂停账号脚本
     */
    private void pauseAccountScript(Integer accountId) {
        try {
            Account account = accountRepository.findById(accountId).orElse(null);
            if (account != null) {
                // 这里可以设置账号状态为暂停状态
                // 具体实现根据现有的账号状态管理逻辑
                log.info("账号脚本已暂停: accountId={}", accountId);
            }
        } catch (Exception e) {
            log.error("暂停账号脚本失败: accountId={}", accountId, e);
        }
    }

    /**
     * 从备注中提取币种信息
     */
    private String getSymbolFromRemark(String remark) {
        // 这里可以根据实际的备注格式来提取币种信息
        // 暂时返回默认值
        return "未知币种";
    }

    /**
     * 检查字符串是否有值
     */
    private boolean hasValue(String str) {
        return str != null && !str.trim().isEmpty();
    }
}